﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace SpecialKey
{
    public class Hotkeys
    {
        public enum KeyFlags
        {
            MOD_ALT = 0x1,
            MOD_CONTROL = 0x2,
            MOD_SHIFT = 0x4,
            MOD_WIN = 0x8
        }
        /// <summary>
        /// 注册热键处理函数
        /// </summary>
        /// <param name="hWnd">用于处理热键消息的窗体句柄</param>
        /// <param name="id">热键的编号</param>
        /// <param name="controlKey">控制键</param>
        /// <param name="virtualKey">热键的虚键编码</param>
        /// <returns>
        ///     <c>true</c>：注册成功<br/>
        ///     <c>false</c>：注册失败
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [ZengE]               2009-7-8 22:28    创建
        /// </history>
        [DllImport("user32")]
        public static extern bool RegisterHotKey(IntPtr hWnd, int id, uint controlKey, uint virtualKey);

        /// <summary>
        /// 注销指定的热键
        /// </summary>
        /// <param name="hWnd">用于处理热键消息的窗体句柄</param>
        /// <param name="id">要注销的热键编号</param>
        /// <returns>
        ///     <c>true</c>：注销成功<br/>
        ///     <c>false</c>：注销失败
        /// </returns>
        /// <remarks></remarks>
        /// <history>
        /// [ZengE]               2009-7-8 22:30    创建
        /// </history>
        [DllImport("user32")]
        public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
        /// <summary>
        /// 安装热键处理挂钩
        /// </summary>
        /// <param name="window">The window.</param>
        /// <returns>
        ///     <c>true</c>：安装成功<br/>
        ///     <c>false</c>：安装失败
        /// </returns>
        /// <value>消息源</value>
        /// <remarks></remarks>
        /// <history>
        /// [ZengE]               2009-7-8 23:57    创建
        /// </history> 
        public static bool InstallHotKeyHook(Window window)
        {
            //判断组件是否有效
            if (null == window)
            {
                //如果无效，则直接返回
                return false;
            }
            sk = window;

            //获得窗体的句柄
            WindowInteropHelper helper = new WindowInteropHelper(window);

            //判断窗体句柄是否有效
            if (IntPtr.Zero == helper.Handle)
            {
                //如果句柄无效，则直接返回
                return false;
            }

            //获得消息源
            HwndSource source = HwndSource.FromHwnd(helper.Handle);

            //判断消息源是否有效
            if (null == source)
            {
                //如果消息源无效，则直接返回
                return false;
            }

            //挂接事件
            source.AddHook(HotKeyHook);

            //返回安装成功
            return true;
        }


        private static Window sk;

        /// <summary>
        /// 热键处理过程
        /// </summary>
        /// <param name="hwnd">触发消息的窗口句柄</param>
        /// <param name="msg">要被处理的消息编号</param>
        /// <param name="wParam">消息参数</param>
        /// <param name="lParam">消息参数</param>
        /// <param name="handled">消息是否被处理</param>
        /// <returns></returns>
        /// <remarks></remarks>
        /// <history>
        /// [ZengE]               2009-7-8 23:54    创建
        /// </history> 
        private static IntPtr HotKeyHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            //判断是否为热键消息
            if (msg == WM_HOTKEY)
            {

                if (Show)
                    sk.Hide();
                else
                    sk.Show();



                var isShow = Show ? SW_HIDE : SW_SHOW;
                Show = !Show;
                foreach (var item in SkItem.ProcessIds)
                {
                    var handle = IntPtr.Zero;
                    if (item.Value.Handle == IntPtr.Zero)
                    {
                        //var p = Process.GetProcessById(item.Key);
                        handle = FindWindowEx(IntPtr.Zero, IntPtr.Zero, null, item.Value.Title);

                        while (SkItem.ProcessIds.Any(s => s.Value.Handle == handle))
                        {
                            if (handle == IntPtr.Zero)
                                break;

                            do
                            {
                                try
                                {
                                    handle = FindWindowEx(IntPtr.Zero, handle, null, item.Value.Title);
                                }
                                catch { }
                            } while (handle == IntPtr.Zero);
                        }
                    }
                    if (handle == IntPtr.Zero)
                        continue;

                    item.Value.Handle = handle;
                }

                foreach (var item in SkItem.ProcessIds)
                    ShowWindow(item.Value.Handle, isShow);
            }

            //返回
            return IntPtr.Zero;
        }

        public static bool Show { get; set; } = true;



        private const int SW_HIDE = 0;

        private const int SW_NORMAL = 1;

        private const int SW_MAXIMIZE = 3;

        private const int SW_SHOWNOACTIVATE = 4;

        private const int SW_SHOW = 5;

        private const int SW_MINIMIZE = 6;

        private const int SW_RESTORE = 9;

        private const int SW_SHOWDEFAULT = 10;

        /// <summary>
        /// 热键消息编号
        /// </summary> 
        private const int WM_HOTKEY = 0x0312;

        [DllImport("user32.dll")]
        public static extern int ShowWindow(IntPtr hwnd, int nCmdShow);


        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);
    }
}

